import { HttpService } from '@nestjs/axios';
import { CACHE_MANAGER } from '@nestjs/cache-manager';
import { Cache } from 'cache-manager';
import {
  Inject,
  Injectable,
  InternalServerErrorException,
} from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import {
  Code2SessionResDto,
  GetAccessTokenResDto,
  WECHAT_ACCESS_TOKEN,
  WechatConfig,
} from '../dtos/wechat.dto';
import { Cron } from '@nestjs/schedule';

@Injectable()
export class WechatService {
  options: WechatConfig;
  constructor(
    private readonly configService: ConfigService,
    private readonly httpService: HttpService,
    @Inject(CACHE_MANAGER)
    private readonly cache: Cache,
  ) {
    this.options = {
      appid: this.configService.get<string>('WECHAT_APP_ID'),
      secret: this.configService.get('WECHAT_APP_SECRET'),
    };
    this.httpService.axiosRef.interceptors.request.use(
      (config) => {
        return config;
      },
      (err) => {
        return Promise.reject(err);
      },
    );
    this.httpService.axiosRef.interceptors.response.use(
      (res) => {
        if (res.status) {
        }
        return res;
      },
      (err) => {
        throw new Error(err);
      },
    );
    // 启动自动获取并存储
    this.refreshAccessToken();
  }

  /**
   * 2小时刷新微信ACCESS_TOKEN
   */
  @Cron('* * 2 * * *')
  private refreshAccessToken() {
    this.getAccessToken();
  }

  private setCacheAccessToken(value: string, ttl?: number) {
    this.cache.set(WECHAT_ACCESS_TOKEN, value, ttl);
  }

  private async getCacheAccessToken(): string {
    const token = await this.cache.get(WECHAT_ACCESS_TOKEN);
    if (typeof token === ) {
      return token;
    }
  }

  /**
   * 获取接口访问凭证(自动缓存)
   */
  private async getAccessToken() {
    const res = await this.httpService.axiosRef.get<GetAccessTokenResDto>(
      `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${this.appid}&secret=${this.secret}`,
    );
    //TODO 需要将获取到的ACCESS_TOKEN存入缓存中,并且设置自动获取重置机制

    const { access_token, expires_in } = res.data;
    if (access_token) {
      this.setCacheAccessToken(access_token, expires_in);
    }
    throw new Error(`${WECHAT_ACCESS_TOKEN} invalid.`);
  }

  /**
   * 微信小程序登录
   * @param code `wx.login`获取的`code`
   * @returns 微信小程序登录结果
   */
  async code2session(code: string) {
    const res = await this.httpService.axiosRef.get<Code2SessionResDto>(
      `https://api.weixin.qq.com/sns/jscode2session?appid=${this.appid}&secret=${this.secret}&js_code=${code}&grant_type=authorization_code`,
    );
    const { errcode, errmsg, ...info } = res.data;
    // 这里需要处理一个问题,就是HTTPs状态码不是20X的情况
    if (errcode != 0) {
      // 这里就代表报错了
      throw new InternalServerErrorException(errmsg);
    }
    return Promise.resolve(info);
  }

  /**
   * 快速获取手机号
   * @param code 微信小程序手机号获取凭证
   */
  async getPhoneNumber(code: string) {
    const access_token = this.getCacheAccessToken();
    const res = await this.httpService.axiosRef.post(
      `https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=${access_token}`,
      {
        code,
      },
    );
    console.log(res);
  }
}
